<?php
namespace app\worker;
use app\index\model\WorkermanRecord;
use \GatewayWorker\Lib\Gateway;

require_once  __DIR__.'/mysql-master/src/Connection.php';
// 自动加载类
require_once __DIR__ . '/../../vendor/autoload.php';
date_default_timezone_set('PRC');

/**
 * 主逻辑
 * 主要是处理 onConnect onMessage onClose 三个方法
 * onConnect 和 onClose 如果不需要可以不用实现并删除
 */
class Events
{
    public static function onWorkerStart($businessWorker)
    {
        // 将db实例存储在全局变量中(也可以存储在某类的静态成员中)
        global $db;
        //$db = new \Workerman\MySQL\Connection('127.0.0.1', '3306', 'root', '123456', 'chongdianzhuang');
        $db = new \Workerman\MySQL\Connection('192.168.144.148', '3306', 'charge_ae-iot', 'kckCX7CFpr5d2yLS', 'charge_ae-iot');
    }

    /**
     * 设置数据库
     * @return \Workerman\MySQL\Connection
     */
    public static function setDbInfo (){
        //$sendDb = new \Workerman\MySQL\Connection('127.0.0.1', '3306', 'root', '123456', 'chongdianzhuang');
        $sendDb = new \Workerman\MySQL\Connection('192.168.144.148', '3306', 'charge_ae-iot', 'kckCX7CFpr5d2yLS', 'charge_ae-iot');
        return $sendDb;
    }

    /**
     * @param int $client_id
     * @throws \Exception
     * * 当客户端连接时触发
     * 如果业务不需此回调可以删除onConnect
     * @param int $client_id 连接id
     */
    public static function onConnect($client_id)
    {
        // 通过全局变量获得db实例
        global $db;
        //插入数据
        $dataService = new DataService();
        $insert_id = $dataService->addMsgRecord($db,$client_id,'客户端链接','客户端链接上服务器');
        Gateway::sendToClient($client_id, json_encode(array(
            'type'      => 'init',
            'client_id' => $client_id
        )));
    }

    /**
     * @param $client_id
     * @param $message
     * @throws \Exception
     * *当客户端发来消息时触发
     * @param int $client_id 连接id
     * @param mixed $message 具体消息
     */
    public static function onMessage($client_id, $message)
    {
        //正式连接充电桩
        $setMessage = bin2hex($message);
        //调试用
        //$setMessage = $message;
        // 通过全局变量获得db实例
        global $db;
        //插入数据
        $dataService = new DataService();
        $msgType = substr($setMessage, 10,2);
        $msgTypeList = self::backTypeInfo();
        /*
        $msgTypeInfo = isset($msgTypeList[$msgType]) ? $msgTypeList[$msgType] : $msgType;
        $insertId = false;
        if($msgType == '03'){
            if(date("i:s") == '00:00'){
                $insertId = $dataService->addMsgRecord($db,$client_id,$setMessage,'接受到客户端发送过来的信息-'.$msgTypeInfo);
            }
        }else{
            $insertId = $dataService->addMsgRecord($db,$client_id,$setMessage,'接受到客户端发送过来的信息-'.$msgTypeInfo);
        }
        $logFile = __DIR__.'/log/'.date("Y-m-d").'.txt';
        if(!$insertId){ file_put_contents($logFile,date("Y-m-d H:i:s").'----'.$client_id."--插入上传数据异常-".$msgTypeInfo."--".$setMessage."\r\n",FILE_APPEND);}
        */
        $logFile = __DIR__.'/log/'.date("Y-m-d").'.txt';
        //获取格式化后的数据
        $getData = $dataService->setPostData($setMessage);
        //dump($getData);
        if($getData['code'] == 0 && isset($getData['data'])){
            foreach ($getData['data'] as $key=>$value){
                $dataInfo = $value;
                $dataInfo['use_status'] = strtoupper($dataInfo['use_status']);
                $msgTypeInfo = isset($msgTypeList[$dataInfo['use_status']]) ? $msgTypeList[$dataInfo['use_status']] : $dataInfo['use_status'];
                $insertId = false;
                if($dataInfo['use_status'] == '03'){
                    if(date("i:s") == '00:00'){
                        $insertId = $dataService->addMsgRecord($db,$client_id,$dataInfo['get_content'],'接受到客户端发送过来的信息-'.$msgTypeInfo);
                    }
                }else{
                    $insertId = $dataService->addMsgRecord($db,$client_id,$dataInfo['get_content'],'接受到客户端发送过来的信息-'.$msgTypeInfo);
                }
                if(!$insertId){ file_put_contents($logFile,date("Y-m-d H:i:s").'----'.$client_id."--插入上传数据异常-".$msgTypeInfo."--".$setMessage."\r\n",FILE_APPEND);}
                $checkNumber = $dataService->modBusCRC($dataInfo['sor_number'].$dataInfo['encryption'].$dataInfo['use_status'].$dataInfo['data_info']);
                //数据帧校验域
                if($checkNumber == $dataInfo['check_number'] || strtoupper($checkNumber) == $dataInfo['check_number']){
                    //执行对应的功能
                    switch ($dataInfo['use_status']){
                        case "01":      //充电桩登录
                            $result = $dataService->chargePileLogin($db,$dataInfo,$insertId,$client_id);
                            break;
                        case "03":      //充电桩心跳包
                            $result = $dataService->pileHeartBeat($db,$dataInfo,$insertId,$client_id);
                            break;
                        case "05":      //计费模型验证请求
                            $result = $dataService->checkPileBillingMode($db,$dataInfo,$insertId);
                            break;
                        case "09":      //充电桩计费模型请求
                            $result = $dataService->getPileBillingMode($db,$dataInfo,$insertId);
                            break;
                        case "13":      //上传实时监测数据
                            $result = $dataService->getChargePileData($db,$dataInfo,$insertId);
                            break;
                        case "15":      //充电握手
                            $result = $dataService->chargingHandshake($db,$dataInfo,$insertId);
                            break;
                        case "17":      //参数配置
                            $result = $dataService->chargePileGunSetParameter($db,$dataInfo,$insertId);
                            break;
                        case "19":      //充电结束
                            $result = $dataService->pileEndCharge($db,$dataInfo,$insertId);
                            break;
                        case "1B":      //错误报文
                            $result = $dataService->addErrorContent($db,$dataInfo,$insertId);
                            break;
                        case "1D":      //充电阶段 BMS 中止
                            $result = $dataService->bmsStopCharge($db,$dataInfo,$insertId);
                            break;
                        case "21":      //充电阶段充电机中止
                            $result = $dataService->machineryStopCharge($db,$dataInfo,$insertId);
                            break;
                        case "23":      //充电过程 BMS 需求、充电机输出
                            $result = $dataService->bmsOutData($db,$dataInfo,$insertId);
                            break;
                        case "25":      //充电过程 BMS 信息
                            $result = $dataService->bmsChargeInfo($db,$dataInfo,$insertId);
                            break;
                        case "31":      //充电桩主动申请启动充电
                            $result = $dataService->pileApplyCharge($db,$dataInfo,$insertId);
                            break;
                        case "33":      //远程启机命令回复
                            $result = $dataService->remoteCommandChargeReply($db,$dataInfo,$insertId);
                            break;
                        case "35":      //远程停机命令回复
                            $result = $dataService->remoteStopChargeReply($db,$dataInfo,$insertId);
                            break;
                        case "3B":      //交易记录
                            $result = $dataService->pileTransactionRecords($db,$dataInfo,$insertId);
                            break;
                        case "41":      //余额更新应答
                            $result = $dataService->userMoneyResponse($db,$dataInfo,$insertId);
                            break;
                        case "43":      //卡数据同步应答
                            $result = $dataService->userCardResponse($db,$dataInfo,$insertId);
                            break;
                        case "45":      //离线卡数据清除应答
                            $result = $dataService->deleteUserCardResponse($db,$dataInfo,$insertId);
                            break;
                        case "47":      //离线卡数据查询应答
                            $result = $dataService->selectUserCardResponse($db,$dataInfo,$insertId);
                            break;
                        case "51":      //充电桩工作参数设置应答
                            $result = $dataService->setPileParameterResponse($db,$dataInfo,$insertId);
                            break;
                        case "55":      //对时设置应答
                            $result = $dataService->setPileTimeResponse($db,$dataInfo,$insertId);
                            if($result['code'] == 1 && isset($result['pile_info'])){
                                try {
                                    $clientInfo = ['client_id'=>$client_id];
                                    $sendData = ['set_time'=>date("Y-m-d H:i:s")];
                                    self::sendMsg($result['pile_info'],$clientInfo,$sendData,'setPileTime');
                                } catch (Exception $e) {
                                    $getErrorMessage = $e->getMessage(); // 返回自定义的异常信息
                                    file_put_contents($logFile , date("Y-m-d H:i:s").'----'.$client_id."设置对时异常".$getErrorMessage."\r\n",FILE_APPEND);
                                }
                            }
                            break;
                        case "57":      //计费模型应答
                            $result = $dataService->pileBillingModeResponse($db,$dataInfo,$insertId);
                            break;
                        case "61":      //地锁数据上送（充电桩上送）
                            $result = $dataService->getFloorLockData($db,$dataInfo,$insertId);
                            break;
                        case "63":      //充电桩返回数据（地锁收到遥控地锁升锁与降锁命令指令，响应本数据）
                            $result = $dataService->setFloorLockResponse($db,$dataInfo,$insertId);
                            break;
                        case "91":      //远程重启应答
                            $result = $dataService->setPileRestartResponse($db,$dataInfo,$insertId);
                            break;
                        case "93":      //远程更新应答
                            $result = $dataService->pileLongRangeUpdateResponse($db,$dataInfo,$insertId);
                            break;
                        case "A1":      //充电桩主动申请并充充电
                            $result = $dataService->pileApplyParallelCharge($db,$dataInfo,$insertId);
                            break;
                        case "A3":      //远程并充启机命令回复
                            $result = $dataService->pileParallelChargeResponse($db,$dataInfo,$insertId);
                            break;
                        default:        //充电停止


                    }
                    //dump($result);die;
                    file_put_contents($logFile,date("Y-m-d H:i:s").'----'.$client_id."返回的结果：".json_encode($result,JSON_UNESCAPED_UNICODE)."\r\n",FILE_APPEND);
                    if($result['back_data']){
                        //返回数据
                        Gateway::sendToClient($client_id,hex2bin($result['back_data']));
                    }
                }else{
                    if($insertId) {
                        $db->update('jy_workerman_record')->cols(array('error_info'=>'帧校验域不通过'))->where('id='.$insertId)->query();
                    }
                    file_put_contents($logFile,date("Y-m-d H:i:s").'----'.$client_id."--帧校验域不通过--".$setMessage."\r\n",FILE_APPEND);
                    Gateway::sendToClient($client_id,hex2bin("88"));
                }
            }
        //数据异常
        }else{
            /*
            if($insertId) {
                $db->update('jy_workerman_record')->cols(array('error_info'=>'上传数据解析异常'))->where('id='.$insertId)->query();
            }
            */
            file_put_contents($logFile,date("Y-m-d H:i:s").'----'.$client_id."--上传数据解析异常--".$setMessage."\r\n",FILE_APPEND);
            Gateway::sendToClient($client_id,hex2bin("88"));
        }
    }

    /**
     * 发送信息
     * @param $pileInfo
     * @param $clientInfo
     * @param $data
     * @param $sendType
     * @return array
     */
    public static function sendMsg($pileInfo,$clientInfo,$data,$sendType){
        $db = self::setDbInfo();
        $dataService = new DataService();
        $result = ['code'=>1,'msg'=>'默认数据'];
        $title = '';
        switch ($sendType){
            case "getChargePileDataInfo":      //读取实时监测数据
                $result = $dataService->getChargePileDataInfo($pileInfo,$data);
                $title = '读取实时监测数据';
                break;
            case "platformStartCharge":      //运营平台启动充电桩 运营平台远程控制启机
                $result = $dataService->platformStartCharge($db,$data['user_info'],$pileInfo,$data);
                $title = '运营平台远程控制启机';
                break;
            case "platformStopCharge":      //运营平台停止充电
                $result = $dataService->platformStopCharge($pileInfo,$data);
                $title = '运营平台停止充电';
                break;
            case "updateUserMoney":         //远程账户余额更新
                $result = $dataService->updateUserMoney($pileInfo,$data);
                $title = '远程账户余额更新';
                break;
            case "updateCardData":          //离线卡数据同步
                $result = $dataService->updateCardData($pileInfo,$data);
                $title = '离线卡数据同步';
                break;
            case "deleteCardData":          //离线卡数据清除
                $result = $dataService->deleteCardData($pileInfo,$data);
                $title = '离线卡数据清除';
                break;
            case "selectCardData":          //离线卡数据查询
                $result = $dataService->selectCardData($pileInfo,$data);
                $title = '离线卡数据查询';
                break;
            case "setPileParameter":        //充电桩工作参数设置
                $result = $dataService->setPileParameter($pileInfo,$data);
                $title = '充电桩工作参数设置';
                break;
            case "setPileTime":             //对时设置
                $result = $dataService->setPileTime($pileInfo,$data);
                $title = '对时设置';
                break;
            case "setPileBillingMode":      //计费模型设置
                $modeInfo = $data['mode_info'];
                $result = $dataService->setPileBillingMode($pileInfo,$modeInfo);
                $title = '计费模型设置';
                break;
            case "setFloorLockStatus":      //遥控地锁升锁与降锁命令
                $result = $dataService->setFloorLockStatus($pileInfo,$data);
                $title = '遥控地锁升锁与降锁命令';
                break;
            case "setPileRestart":          //远程重启
                $result = $dataService->setPileRestart($pileInfo,$data);
                $title = '远程重启';
                break;
            case "pileLongRangeUpdate":      //远程更新
                $result = $dataService->pileLongRangeUpdate($pileInfo,$data);
                $title = '远程更新';
                break;
            case "pileParallelCharge":      //运营平台远程控制并充启机
                $result = $dataService->pileParallelCharge($db,$data['user_info'],$pileInfo,$data);
                $title = '运营平台远程控制并充启机';
                break;
            default:
        }
        $logFile = __DIR__.'/log/'.date("Y-m-d").'.txt';
        //发送信息
        if($result['back_data']){
            $sendStatus = true;
            //返回数据
            try {
                //file_put_contents($logFile,date("Y-m-d H:i:s").'----'.$clientInfo['id']."--发送数据--".$result['back_data']."\r\n",FILE_APPEND);
                $dataService->addSendRecord($db,$clientInfo,$title,$result['back_data'],$sendType);
				//dump($result['back_data']);
                Gateway::sendToClient($clientInfo['client_id'],hex2bin($result['back_data']));
            }catch (Exception $e){
                $sendStatus = false;
                file_put_contents($logFile,date("Y-m-d H:i:s").'----'.$clientInfo['id']."--发送数据异常(发送数据)--".$e->getMessage()."\r\n",FILE_APPEND);
            }
        }
        if($sendStatus){
            return $result;
        }else{
            return ['code'=>1,'msg'=>'发送信息到充电桩端失败'];
        }
    }

    /**
     * * 当用户断开连接时触发
     * @param int $client_id 连接id
     * @param $client_id
     * @throws \Exception
     */
    public static function onClose($client_id)
    {
        // 通过全局变量获得db实例
        global $db;
        //插入数据
        $dataService = new DataService();
        $insert_id = $dataService->addMsgRecord($db,$client_id,'客户断开服务端','客户断开服务端');
        //设置对应充电桩和充电枪状态
        $clientWhere = "client_id='".$client_id."' && is_delete=1";
        $clientInfo = $db->select('*')->from('jy_pile_client')->where($clientWhere)->orderByDESC(['id'])->row();
        if($clientInfo && $clientInfo['pile_id']){
            $savePile = [
                'is_use'=>3,
                'update_time'=>date("Y-m-d H:i:s"),
            ];
            $saveGun =[
                'is_status'=>0,
                'update_time'=>date("Y-m-d H:i:s"),
            ];
            $updateClientResult = $db->update('jy_charge_pile')->where('id='.$clientInfo['pile_id'])->cols($savePile)->query();
            $updateGunResult = $db->update('jy_charge_pile_gun')->where('pile_id='.$clientInfo['pile_id'])->cols($saveGun)->query();

        }
        //设置当前链接为无效
        $result = $db->update('jy_pile_client')->cols(['is_delete'=>2,'update_time'=>date("Y-m-d H:i:s")])->where("client_id='".$client_id."'")->query();
        // 向所有人发送
        //GateWay::sendToAll("$client_id logout\r\n");
    }

    /**
     * 返回请求类型
     * @return array
     */
    public static function backTypeInfo(){
        return [
            '01'=>'充电桩登录认证',
            '02'=>'登录认证应答',
            '03'=>'充电桩心跳包',
            '04'=>'心跳包应答',
            '05'=>'计费模型验证请求',
            '06'=>'计费模型验证请求应答',
            '09'=>'充电桩计费模型请求',
            '0A'=>'计费模型请求应答',
            '12'=>'读取实时监测数据',
            '13'=>'离线监测数据',
            '15'=>'充电握手',
            '17'=>'参数配置',
            '19'=>'充电结束',
            '1B'=>'错误报文',
            '1D'=>'充电阶段 BMS 中止',
            '21'=>'充电阶段充电机中止',
            '23'=>'充电过程 BMS 需求、充电机输出',
            '25'=>'充电过程 BMS 信息',
            '31'=>'充电桩主动申请启动充电',
            '32'=>'运营平台确认启动充电',
            '33'=>'远程启机命令回复',
            '34'=>'运营平台远程控制启机',
            '35'=>'远程停机命令回复',
            '36'=>'运营平台远程停机',
            '3B'=>'交易记录',
            '40'=>'交易记录确认',
            '41'=>'余额更新应答',
            '42'=>'远程账户余额更新',
            '43'=>'卡数据同步应答',
            '44'=>'离线卡数据同步',
            '45'=>'离线卡数据清除应答',
            '46'=>'离线卡数据清除',
            '47'=>'离线卡数据查询应答',
            '48'=>'离线卡数据查询',
            '51'=>'充电桩工作参数设置应答',
            '52'=>'充电桩工作参数设置',
            '55'=>'对时设置应答',
            '56'=>'对时设置',
            '57'=>'计费模型应答',
            '58'=>'计费模型设置',
            '61'=>'地锁数据上送（充电桩上送）',
            '62'=>'遥控地锁升锁与降锁命令（下行）',
            '63'=>'充电桩返回数据（上行）',
            '91'=>'远程重启应答',
            '92'=>'远程重启',
            '93'=>'远程更新应答',
            '94'=>'远程更新',
            'A1'=>'充电桩主动申请并充充电',
            'A2'=>'运营平台确认并充启动充电',
            'A3'=>'远程并充启机命令回复',
            'A4'=>'运营平台远程控制并充启机',
        ];
    }

}
